/**
 * create by zhike
 * date:2015年3月2日
 */
package com.acooly.module.openapi.client.provider.wsbank;

import com.acooly.core.utils.Strings;
import com.acooly.core.utils.net.HttpResult;
import com.acooly.module.openapi.client.api.AbstractApiServiceClient;
import com.acooly.module.openapi.client.api.exception.ApiClientException;
import com.acooly.module.openapi.client.api.exception.ApiClientSocketTimeoutException;
import com.acooly.module.openapi.client.api.exception.ApiServerException;
import com.acooly.module.openapi.client.api.marshal.ApiMarshal;
import com.acooly.module.openapi.client.api.marshal.ApiUnmarshal;
import com.acooly.module.openapi.client.api.message.PostRedirect;
import com.acooly.module.openapi.client.api.transport.Transport;
import com.acooly.module.openapi.client.provider.wsbank.domain.WsbankNotify;
import com.acooly.module.openapi.client.provider.wsbank.domain.WsbankRequest;
import com.acooly.module.openapi.client.provider.wsbank.domain.WsbankResponse;
import com.acooly.module.openapi.client.provider.wsbank.exception.WsbankApiClientProcessingException;
import com.acooly.module.openapi.client.provider.wsbank.marshall.*;
import com.acooly.module.openapi.client.provider.wsbank.message.WsbankUploadImgRequest;
import com.acooly.module.openapi.client.provider.wsbank.utils.HttpsUtil;
import com.acooly.module.openapi.client.provider.wsbank.utils.SignUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.StringBody;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.SortedMap;

/**
 * ApiService执行器
 *
 * @author zhike
 */
@Component("wsbankApiServiceClient")
@Slf4j
public class WsbankApiServiceClient
        extends AbstractApiServiceClient<WsbankRequest, WsbankResponse, WsbankNotify, WsbankNotify> {


    public static final String PROVIDER_NAME = "wsbank";

    @Resource(name = "wsbankHttpTransport")
    private Transport transport;

    @Resource(name = "wsbankRequestMarshall")
    private WsbankRequestMarshall requestMarshal;

    @Resource(name = "wsbankRedirectMarshall")
    private WsbankRedirectMarshall redirectMarshal;

    @Resource(name = "wsbankSignMarshall")
    private WsbankSignMarshall signMarshall;

    @Resource(name = "wsbankRedirectPostMarshall")
    private WsbankRedirectPostMarshall wsbankRedirectPostMarshall;

    @Autowired
    private WsbankResponseUnmarshall responseUnmarshal;
    @Autowired
    private WsbankNotifyUnmarshall notifyUnmarshal;

    @Autowired
    private OpenAPIClientWsbankProperties openAPIClientJytProperties;

    @Override
    public WsbankResponse execute(WsbankRequest request) {
        try {
            beforeExecute(request);
            if(Strings.isBlank(request.getGatewayUrl())) {
                request.setGatewayUrl(openAPIClientJytProperties.getGatewayUrl());
            }
            //组装请求报文头
            String url = request.getGatewayUrl();
            String requestMessage = getRequestMarshal().marshal(request);
            log.info("请求报文: {}", requestMessage);
            HttpResult result = getTransport().request(requestMessage, url);
            if (result.getStatus() >= HttpStatus.SC_BAD_REQUEST) {
                throw new RuntimeException("HttpStatus:" + result.getStatus());
            }
            if(Strings.isBlank(result.getBody())) {
                throw new ApiClientException("响应报文为空");
            }
            WsbankResponse t = getResponseUnmarshal().unmarshal(result.getBody(), request.getService());
            afterExecute(t);
            return t;
        } catch (WsbankApiClientProcessingException pe) {
            log.error("解析响应报文异常：" + pe.getMessage(), pe);
            throw pe;
        } catch (ApiClientSocketTimeoutException ase) {
            log.error("响应超时异常：" + ase.getMessage(), ase);
            throw new WsbankApiClientProcessingException(ase.getMessage());
        } catch (ApiServerException ose) {
            log.error("服务器:" + ose.getMessage(), ose);
            throw ose;
        } catch (ApiClientException oce) {
            log.error("客户端:" + oce.getMessage(), oce);
            throw oce;
        } catch (Exception e) {
            log.error("内部错误:" + e.getMessage(), e);
            throw new ApiClientException("内部错误:" + e.getMessage());
        }
    }

    /**
     * 图片上传
     * @param request
     * @return
     */
    public WsbankResponse executeUploadImg(WsbankUploadImgRequest request) {
        try {
            beforeExecute(request);
            if(Strings.isBlank(request.getGatewayUrl())) {
                request.setGatewayUrl(openAPIClientJytProperties.getGatewayUrl());
            }
            //组装请求报文头
            String gatewayUrl = request.getGatewayUrl();
            SortedMap<String,String> formData = SignUtils.getSignDataMap(request);
            String signStr = SignUtils.urlEncode(SignUtils.getSignContent(formData));
            log.info("待签字符串：{}",signStr);
            HttpEntity reqEntity = MultipartEntityBuilder.create()
                    .addPart("IsvOrgId", new StringBody(request.getIsvOrgId(),ContentType.DEFAULT_TEXT))
                    .addPart("PhotoType", new StringBody(request.getPhotoType(),ContentType.DEFAULT_TEXT))
                    .addPart("OutTradeNo", new StringBody(request.getOutTradeNo(),ContentType.DEFAULT_TEXT))
                    .addBinaryBody("Picture", request.getPicture())
                    .addPart("Function", new StringBody(request.getFunction(),ContentType.DEFAULT_TEXT))
                    .addPart("Version", new StringBody(request.getVersion(),ContentType.DEFAULT_TEXT)).addPart("AppId", new StringBody(request.getAppId(),ContentType.DEFAULT_TEXT))
                    .addPart("ReqTime", new StringBody(request.getReqTime(),ContentType.DEFAULT_TEXT))
                    .addPart("Signature", new StringBody(signMarshall.uploadDoSign(signStr),ContentType.DEFAULT_TEXT)).build();
            //发送请求
            String response = HttpsUtil.httpPost(gatewayUrl, reqEntity);
            if(Strings.isBlank(response)) {
                throw new ApiClientException("响应报文为空");
            }
            WsbankResponse t = getResponseUnmarshal().unmarshal(response, request.getService());
            afterExecute(t);
            return t;
        } catch (WsbankApiClientProcessingException pe) {
            log.error("解析响应报文异常：" + pe.getMessage(), pe);
            throw pe;
        } catch (ApiClientSocketTimeoutException ase) {
            log.error("响应超时异常：" + ase.getMessage(), ase);
            throw new WsbankApiClientProcessingException(ase.getMessage());
        } catch (ApiServerException ose) {
            log.error("服务器:" + ose.getMessage(), ose);
            throw ose;
        } catch (ApiClientException oce) {
            log.error("客户端:" + oce.getMessage(), oce);
            throw oce;
        } catch (Exception e) {
            log.error("内部错误:" + e.getMessage(), e);
            throw new ApiClientException("内部错误:" + e.getMessage());
        }
    }

    public WsbankNotify notice(HttpServletRequest request, String serviceKey) {
        try {
            Map<String,String> notifyData = getSignMarshall().getDateMap(request);
            WsbankNotify notify = getNoticeUnmarshal().unmarshal(notifyData, serviceKey);
            afterNotice(notify);
            return notify;
        } catch (ApiClientException oce) {
            log.warn("客户端:{}", oce.getMessage());
            throw oce;
        } catch (Exception e) {
            log.warn("内部错误:{}", e.getMessage());
            throw new ApiClientException("内部错误:" + e.getMessage());
        }
    }

    @Override
    public PostRedirect redirectPost(WsbankRequest request) {
        try {
            beforeExecute(request);
            PostRedirect postRedirect = wsbankRedirectPostMarshall.marshal(request);
            return postRedirect;
        } catch (ApiServerException ose) {
            log.error("服务器:" + ose.getMessage(), ose);
            throw ose;
        } catch (ApiClientException oce) {
            log.error("客户端:" + oce.getMessage(), oce);
            throw oce;
        } catch (Exception e) {
            log.error("内部错误:" + e.getMessage(), e);
            throw new ApiClientException("内部错误:" + e.getMessage());
        }
    }

    @Override
    protected ApiMarshal<String, WsbankRequest> getRequestMarshal() {
        return this.requestMarshal;
    }

    @Override
    protected ApiUnmarshal<WsbankResponse, String> getResponseUnmarshal() {
        return this.responseUnmarshal;
    }

    @Override
    protected ApiUnmarshal<WsbankNotify, Map<String, String>> getNoticeUnmarshal() {
        return this.notifyUnmarshal;
    }

    @Override
    protected ApiMarshal<String, WsbankRequest> getRedirectMarshal() {
        return this.redirectMarshal;
    }

    @Override
    protected Transport getTransport() {
        return this.transport;
    }

    @Override
    protected ApiUnmarshal<WsbankNotify, Map<String, String>> getReturnUnmarshal() {
        return this.notifyUnmarshal;
    }

    public WsbankSignMarshall getSignMarshall() {
        return signMarshall;
    }

    public void setSignMarshall(WsbankSignMarshall signMarshall) {
        this.signMarshall = signMarshall;
    }

    @Override
    public String getName() {
        return PROVIDER_NAME;
    }
}
